﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Threading;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace Минуточка
{
    public class Event:DependencyObject, IDisposable
    {
        DispatcherTimer timer = new DispatcherTimer();
        private DateTime _timerdate;
        
        public string Descr
        {
            get { return (string)GetValue(DescrProperty); }
            set { SetValue(DescrProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Descr.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DescrProperty =
            DependencyProperty.Register("Descr", typeof(string), typeof(Event), new UIPropertyMetadata(""));


        public string Date
        {
            get { return (string)GetValue(DateProperty); }
            set { SetValue(DateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Date.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DateProperty =
            DependencyProperty.Register("Date", typeof(string), typeof(Event), new UIPropertyMetadata(DateTime.Now.ToString("dd.MM.yyyy HH:mm")));


        public Brush Color
        {
            get { return (Brush)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Brush), typeof(Event), new UIPropertyMetadata(Brushes.LightGray));

        public Brush Color2
        {
            get { return (Brush)GetValue(Color2Property); }
            set { SetValue(Color2Property, value); }
        }

        // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Color2Property =
            DependencyProperty.Register("Color2", typeof(Brush), typeof(Event), new UIPropertyMetadata(Brushes.LightGray));


        public string Elapsed
        {
            get { return (string)GetValue(ElapsedProperty); }
            private set { SetValue(ElapsedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Elapsed.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElapsedProperty =
            DependencyProperty.Register("Elapsed", typeof(string), typeof(Event), new UIPropertyMetadata());



        public string Format
        {   
            get { return (string)GetValue(FormatProperty); }
            set { SetValue(FormatProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Format.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FormatProperty =
            DependencyProperty.Register("Format", typeof(string), typeof(Event), new UIPropertyMetadata(""));



        public Visibility EditVisibility
        {
            get { return (Visibility)GetValue(EditVisibilityProperty); }
            set { SetValue(EditVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowEdit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EditVisibilityProperty =
            DependencyProperty.Register("EditVisibility", typeof(Visibility), typeof(Event), new UIPropertyMetadata(Visibility.Collapsed));



        public Visibility ShowVisibility
        {
            get { return (Visibility)GetValue(ShowVisibilityProperty); }
            set { SetValue(ShowVisibilityProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ShowVisibility.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ShowVisibilityProperty =
            DependencyProperty.Register("ShowVisibility", typeof(Visibility), typeof(Event), new UIPropertyMetadata(Visibility.Visible));




        public EventNotifyType EventNotify
        {
            get { return (EventNotifyType)GetValue(EventNotifyProperty); }
            set { SetValue(EventNotifyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EventNotify.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EventNotifyProperty =
            DependencyProperty.Register("EventNotify", typeof(EventNotifyType), typeof(Event), new UIPropertyMetadata(EventNotifyType.None));



        public string DateToolTip
        {
            get { return (string)GetValue(DateToolTopProperty); }
            set { SetValue(DateToolTopProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DateToolTop.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DateToolTopProperty =
            DependencyProperty.Register("DateToolTop", typeof(string), typeof(Event), new UIPropertyMetadata(string.Empty));




        public string Sound
        {
            get { return (string)GetValue(SoundProperty); }
            set { SetValue(SoundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Sound.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SoundProperty =
            DependencyProperty.Register("Sound", typeof(string), typeof(Event), new UIPropertyMetadata(""));




        public long TotalSeconds
        {
            get { return (long)GetValue(TotalSecondsProperty); }
            set { SetValue(TotalSecondsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TotalSeconds.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TotalSecondsProperty =
            DependencyProperty.Register("TotalSeconds", typeof(long), typeof(Event), new UIPropertyMetadata(0L));



        public long ElapsedSeconds
        {
            get { return (long)GetValue(ElapsedSecondsProperty); }
            set { SetValue(ElapsedSecondsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElapsedSeconds.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElapsedSecondsProperty =
            DependencyProperty.Register("ElapsedSeconds", typeof(long), typeof(Event), new UIPropertyMetadata(0L));



        private static List<Brush> _colors;
        public List<Brush> Colors
        {
            get { return _colors; }
        }

        static Event()
        {
            _colors = (from p in typeof(Brushes).GetProperties()
                       select ((Brush)p.GetValue(null, null)).Clone()).ToList();

        }

        public XmlNode Source
        {
            get { return _source; }
        }

        private XmlNode _source;
        private XmlNode _oldsource;
        public Event(XmlNode source)
        {
            timer.Stop();
            _source = source;

            Load(source);
            
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Start();
        }

        private void Load(XmlNode source)
        {
            try
            {
                Descr = source.InnerText;
                Date = source.Attributes["Date"].Value;
                Format = source.Attributes["Format"].Value;
                Color = _colors.First(c => c.ToString() == source.Attributes["Color"].Value);
                EventNotify = (EventNotifyType)(int.Parse(source.Attributes["EventNotify"].Value));
                Sound = source.Attributes["Sound"].Value;

                Color2 = Color;

                GenerateDate();

                

                if (Date.IndexOf("_") > -1)
                    DateToolTip = _timerdate.ToString("dd.MM.yyyy HH:mm:ss (" + Date + ")");
                else
                    DateToolTip = Date;

                timer.Start();
            }
            catch (Exception)
            {
                
                
            }
        }

        void GenerateDate()
        {
             string format = "";
             if (Date.IndexOf("_") > -1)
             {

                 string now = DateTime.Now.ToString("dd.MM.yyyy HH:mm");
                 int i = 0;
                 foreach (char c in Date.ToCharArray())
                 {
                     if (c == '_')
                         format += now[i];
                     else
                         format += c;
                     i++;
                 }

                 //если у нас ежеминутно - добавляем еще и секунды
                 if (Date.EndsWith("__"))
                     format += ":59";
                 
             }
             else
                 format = Date;

             _timerdate = DateTime.Parse(format);

             TotalSeconds =Math.Abs((long)_timerdate.Subtract(DateTime.Now).TotalSeconds);
        }

        void timer_Tick(object sender, EventArgs e)
        {
            TimeSpan elapsed = DateTime.Now.Subtract(_timerdate);
            DateTime d;

            if (elapsed.TotalMilliseconds > 0)
            {
                Color2 = Brushes.Red;
                if (Date.IndexOf("_") > -1) GenerateDate();
                
                if ((int)elapsed.TotalSeconds == 0)
                    UserNotify();
                ElapsedSeconds = 0;
                //TotalSeconds = 0;
            }
            else
            {
                Color2 = Color;
                ElapsedSeconds = (long)Math.Abs(TotalSeconds + elapsed.TotalSeconds);
            }
            //Debug.WriteLine(elapsed.TotalSeconds);



           
            Debug.WriteLine(TotalSeconds.ToString() + " " + ElapsedSeconds.ToString());

            d = new DateTime(Math.Abs(elapsed.Ticks));
            Elapsed = Format
                .Replace("yy", (d.Year-1).ToString("00"))
                .Replace("MM", (d.Month - 1).ToString("00"))
                .Replace("dd", (d.Day - 1).ToString("00"))
                .Replace("HH", ((int)Math.Abs(elapsed.Hours)).ToString("00"))
                .Replace("mm", ((int)Math.Abs(elapsed.Minutes)).ToString("00"))
                .Replace("ss", ((int)Math.Abs(elapsed.Seconds)).ToString("00"))
                .Replace("ДД", ((int)Math.Abs(elapsed.TotalDays)).ToString("0,0"))
                .Replace("чч", ((int)Math.Abs(elapsed.TotalHours)).ToString("0,0"))
                .Replace("мм", ((int)Math.Abs(elapsed.TotalMinutes)).ToString("0,0"))
                .Replace("сс", ((int)Math.Abs( elapsed.TotalSeconds)).ToString("0,0"));
            //Debug.WriteLine(elapsed.ToString() + Descr);
        }

        private void UserNotify()
        {
            if ((EventNotify & EventNotifyType.Beep) == EventNotifyType.Beep)
            {
                System.Media.SystemSounds.Beep.Play();
            }
            if ((EventNotify & EventNotifyType.Tray) == EventNotifyType.Tray)
            {
                if (ToTray != null)
                    ToTray(this);
            }
            if ((EventNotify & EventNotifyType.Sound) == EventNotifyType.Sound)
            {
                if (File.Exists(Sound))
                {
                    MediaPlayer mp = new MediaPlayer();
                    mp.Open( new Uri(Sound, UriKind.Absolute));
                    mp.Play();
                }

            }
            if ((EventNotify & EventNotifyType.Message) == EventNotifyType.Message)
            {
                //MessageBox.Show(Descr, "Время вышло!", MessageBoxButton.OK, MessageBoxImage.Warning);
                 new Thread(new ParameterizedThreadStart(delegate(object mes) 
                    {
                        MessageBox.Show(mes.ToString(), "Время вышло!", MessageBoxButton.OK, MessageBoxImage.Warning);
                    })).Start(Descr);
            }
        }

        public void BeginEdit()
        {
            _oldsource = _source.Clone();
            ShowVisibility = Visibility.Collapsed;
            EditVisibility = Visibility.Visible;
            timer.Stop();
        }

        public void Commit()
        {
            _source.InnerText = Descr;
            _source.Attributes["Date"].Value = Date.ToString();
            _source.Attributes["Format"].Value = Format;
            _source.Attributes["Color"].Value = Color.ToString();
            _source.Attributes["EventNotify"].Value = ((int)EventNotify).ToString();
            _source.Attributes["Sound"].Value = Sound;
            _source.OwnerDocument.Save(wMain._file);

            Load(_source);

            EndEdit();
        }

        public void EndEdit()
        {

            _oldsource = null; 
            ShowVisibility = Visibility.Visible;
            EditVisibility = Visibility.Collapsed;
            timer.Start();
        }

        public void CancelEdit()
        {
            if (_oldsource != null) Load(_oldsource);
            EndEdit();
        }

        public event ToTray ToTray;

        #region IDisposable Members

        public void Dispose()
        {
            timer.Stop();
            _source = null;
        }

        #endregion

        public override string ToString()
        {
            return Descr + ": " + Elapsed;
        }
    }

    public enum EventNotifyType
    {
        None =0,
        Beep = 1,
        Message = 2,
        Tray = 4,
        Sound = 8
    }

    public delegate void ToTray(Event sender);
}
